﻿using System;
using System.Collections.Generic;
using System.IO;
using CSJ2K.Util.IO;

namespace CSJ2K.Jpc.Segments
{
    /// <summary>Progression order change (POC)</summary>
    /// <comment>
    /// Function: Describes the bounds and progression order for any progression order other 
    ///      than specified in the COD marker segments in the codestream. 
    /// Usage: Main and tile-part headers. At most one POC marker segment may appear in any 
    ///      header. However, several progressions can be described with one POC marker segment.
    ///      If a POC marker segment is used in the main header, it overrides the progression 
    ///      order in the main and tile COD marker segments. If a POC is used to describe the 
    ///      progression of a particular tile, a POC marker segment must appear in the first 
    ///      tile-part header of that tile. Thus, the progression order of a given tile is 
    ///      determined by the presence of the POC or the values of the COD in the following 
    ///      order of precedence: 
    ///          Tile-part POC > Main POC > Tile-part COD > Main COD 
    ///      where the "greater than" sign, >, means that the greater overrides the lessor 
    ///      marker segment.  In the case where a POC marker segment is used, the progression 
    ///      of every packet in the codestream (or for that tile of the codestream) shall be 
    ///      defined in one or more POC marker segments. Each progression order is described in
    ///      only one POC marker segment and shall be described in any tile-part header before 
    ///      any packets of that progression are found. 
    /// Length: Variable depending on the number of different progressions.
    /// </comment>
    public class POC : Segment
    {
        public struct ProgressionInfo
        {
            /// <summary>Resolution level index (inclusive) for the start of a progression.</summary>
            public byte RS;      

            /// <summary>Component index (inclusive) for the start of a progression. (8 or 16 bit dep. on Csiz)</summary>
            public ushort CS;    

            /// <summary>Layer index (exclusive) for the end of a progression.</summary>
            public ushort LYE;

            /// <summary>Resolution Level index (exclusive) for the end of a progression.</summary>
            public byte RE;

            /// <summary>Component index (exclusive) for the end of a progression.</summary>
            public ushort CE;

            /// <summary>Progression Order.  (8 or 16 bits dep. on SIZ.C)</summary>
            public byte P;
        }

        /// <summary>One value for each progression change in this tile-part.</summary>
        public ProgressionInfo[] Progression;

        public POC(Stream source)
            : this(source, (Markers)StreamUtil.ReadBUInt16(source)) { }
        public POC(Stream source, Markers marker)
            : base(source, marker, true)
        {
            if (marker == Markers.POC) throw (new ApplicationException("Attempting to create segment of the wrong type."));

            Progression = new ProgressionInfo[(Length - 2) / 9];
            for(int i=0; i<Progression.Length; i++)
            {
                Progression[i].RS = StreamUtil.ReadOctet(source);
                Progression[i].CS = StreamUtil.ReadBUInt16(source);
                Progression[i].LYE = StreamUtil.ReadBUInt16(source);
                Progression[i].RE = StreamUtil.ReadOctet(source);
                Progression[i].CE = StreamUtil.ReadBUInt16(source);
                Progression[i].P = StreamUtil.ReadOctet(source);
            }
        }
    }
}
